# -*- coding:utf-8 -*-
# @Time : 2022/11/18 21:49
# @Author : 谢天

#from time_converte import TimeConverter  #自己写的Seconds past midnight到24小时制时间转换的类
import pandas as pd
import math
import os
from tkinter import *
from tkinter import ttk
import tkinter.filedialog
import warnings
from functools import lru_cache
warnings.filterwarnings("ignore")

import re
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,NavigationToolbar2Tk #NavigationToolbar2TkAgg
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
mpl.rcParams['font.sans-serif'] = ['SimHei']  # 中文显示
mpl.rcParams['axes.unicode_minus'] = False  # 负号显示
pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)
#pd.set_option('display.colheader_justify', 'right')
#各操作标记参数
range_control = 0   #标记画布范围是否被改动过
addbj = 0
delbj = 0
chabj = 0
rtcha = 0
conmouse = 0
ys_ss = 'ss'
# 数据处理相关数据结构
notemenu = []    #断面存储列表
notesection =[]  #下拉框显示目录，关联断面序号
dmnum = 0  #断面序号
scrpoint = 0 #点间隔距离
Retracebox = []     #回撤栈存储列表
Remove_source = []  #回撤时，删除点位置追踪存

# 保证刷新后保持缩放状态的参数
press2 = 0
lastx = 0
lasty = 0
new_xstart = 0
new_xend = 0
new_ystart = 0
new_yend = 0

#创建全局变量_与成图据相关的数据结构
line_numbers = {}
ys_ZZFIX = {}
XH = {}
EC1 = {}
fix = {}
add = {}
ysdel = {}
POS = {}
FIX = {}
ADD = {}
CHA = {}
dfEC1 = {}
dfFIX = {}
ZZFIX = {}
dfADD = {}
dfDEL = {}
dfCHA = {}
ytfx = []  #控制是否显示原图
#######待解决问题
#尝试转plotly库提速（失败，后期放弃使用tkinter转QT也许可以再提速）
#增加应错机制，遇到错误数据如何处理.用try语句大致解决。
#多波束处理尚未添加，后续尝试
#优化界面，美观（当点很密时，看起来不方便，颜色不显得高端）

#下拉框和切换断面
def select_section(event):
    global dmnum
    dmnum= notesection.index(combo_box.get())  # 获得当前选择的下拉框的序号
    combo_box.current(dmnum)
    operation()
    fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
def dminc():
    global dmnum
    if len(notemenu) == 0:
        tkinter.messagebox.showwarning('警告', '请先加载数据')
        return
    if dmnum < len(notemenu)-1:
        dmnum += 1
        combo_box.current(dmnum)
        operation()
        fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
    else:
        tkinter.messagebox.showwarning('警告', '已在最后一条断面')
def dmdec():
    global dmnum
    if len(notemenu) == 0:
        tkinter.messagebox.showwarning('警告', '请先加载数据')
        return
    if dmnum > 0:
        dmnum -= 1
        combo_box.current(dmnum)
        operation()
        fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
    else:
        tkinter.messagebox.showwarning('警告', '已在第一条断面')
#设置筛点点距
def screen_point():
    global scrpoint,range_control,dmnum
    x = entrypiont.get()
    if x.isdigit():
        scrpoint = float(x)
        range_control = 0
        process_date()
        operation()
        fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
#显示原始绘图
def ytfxbj():
    global ytfx,range_control
    if ytfx[dmnum] == 0:
        ytfx[dmnum] =1   #为1是会显示原图
    else:
        ytfx[dmnum] =0
    range_control = 0
    process_date()
    operation()
    fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
#鼠标操作增、删、输入改、拖拽改
def radd():
    global addbj,delbj,chabj,rtcha
    addbj = 1
    delbj = 0
    chabj = 0
    rtcha = 0
    root.config(cursor="crosshair")
def dele():
    global addbj,delbj,chabj,rtcha
    addbj = 0
    delbj = 1
    chabj = 0
    rtcha = 0
    root.config(cursor="crosshair")
def cha():
    global addbj,delbj,chabj,rtcha
    addbj = 0
    delbj = 0
    chabj = 1
    rtcha = 0
    root.config(cursor="crosshair")
def btimt_d_bj():
    global addbj,delbj,chabj,rtcha
    addbj = 0
    delbj = 0
    chabj = 0
    rtcha = 1
    root.config(cursor="crosshair")
    #root.config(cursor="arrow") 这是变回箭头
#批量处理，并显示加载进度
def load_progress():
    global dmnum,ytfx
    #添加进度条控件
    label3.config(text="加载进度")
    progress = ttk.Progressbar(frame, orient=HORIZONTAL, length=200, mode='determinate')
    progress.pack(side=LEFT, padx=5,pady=0)
    addsum = 0
    for i in range(len(notesection)):
        ytfx.append(0)
        dmnum = i
        try:
            process_date()
        except:
            pass
        progress['value'] = int((i + 1) / len(notesection) * 100)
        root.update()  # 实时刷新UI
        # print(f'Progress: {i + 1}/{len(notesection)}')
        addsum += len(dfADD[dmnum])
    print('加点总计：',addsum)
    # 在循环结束后销毁进度条控件
    label3.config(text='')
    progress.destroy()
#导入文件
def import_date():
    global notemenu,notesection
    global fig,fig1,filepath,dmnum
    file_in = tkinter.filedialog.askopenfilename(filetypes=(('LOG file', '*.LOG'),))  # 获取路径
    if file_in == '':
        pass
    else:
        (filepath, tempfilename) = os.path.split(file_in)  # 路径分成文件夹路径和文件名
        filepath = filepath.replace('/', '\\')
        (filename, extension) = os.path.splitext(tempfilename)  # 文件分成文件不带后缀的文件名和后缀
    notesection = []
    notemenu = []
    with open(file_in, 'r') as f:
        for i in f:
            i = i.strip('\n')
            # 定位文件名中的位置信息，作为日志文件名的一部分
            e = i.rfind('\\')
            fi = i[e+1:]
            i = filepath +'\\' + fi
            notesection.append(fi)
            notemenu.append(i)
    # print(notesection)
    # print(notemenu)
    #####图像处理部分#####
    try:
        fig
    except NameError:
        # 创建绘图对象f
        fig = plt.figure(num=2, figsize=(25, 15), dpi=80, facecolor="pink", edgecolor='green', frameon=True)
        # 创建一副子图
        fig1 = plt.subplot(1, 1, 1)
        # 创建画布并在主窗口上显示
        canvas = FigureCanvasTkAgg(fig, master=root)
        # canvas = FigureCanvasQTAgg(fig, master=root)
        canvas.draw()
        canvas.get_tk_widget().pack()
    else:
        pass

    load_progress()
    dmnum = 0
    operation()
    fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
    #将断面名称置于下拉框
    combo_box['value'] = notesection
    combo_box.current(0)
#处理文件
def process_date():
    global EC1,fix,POS,FIX,ADD,CHA,ysdel,add
    global dfDEL,dfADD,dfCHA,dfEC1,dfFIX,ZZFIX,ys_ZZFIX
    global fig,fig1,XH,notemenu,line_numbers
    global xz_min, xz_max,yz_min, yz_max

    # 将字典里键dmnum对应的值定义为空列表和dataframe
    line_numbers[dmnum] = []
    EC1[dmnum] = []
    fix[dmnum] = []
    add[dmnum] = []
    ysdel[dmnum] = []
    POS[dmnum] = []
    FIX[dmnum] = []
    ADD[dmnum] = []
    CHA[dmnum] = []
    XH[dmnum] = []
    dfEC1[dmnum] = pd.DataFrame()
    dfFIX[dmnum] = pd.DataFrame()
    ZZFIX[dmnum] = pd.DataFrame()
    dfADD[dmnum] = pd.DataFrame()
    dfDEL[dmnum] = pd.DataFrame()
    dfCHA[dmnum] = pd.DataFrame()
    ys_ZZFIX[dmnum] = pd.DataFrame()

    #打印断面文件名
    print(notemenu[dmnum])
    with open(notemenu[dmnum], 'r') as note:
    #note = open(notemenu[dmnum], 'r')
        # 定义正则表达式
        date_regex = re.compile(r'\bTND.+')
        location_regex = re.compile(r'\bPTS\s.+')
        fix_regex = re.compile(r"\bFIX .+")
        ec1_regex = re.compile(r"\bEC1 1.+")
        pos_regex = re.compile(r"\bPOS .+")
        # 修改后正则表达式
        add_regex = re.compile(r"\bAdd.+")
        cha_regex = re.compile(r"\bCha.+")
        del_regex = re.compile(r"\bDel.+")
        # 遍历文件并匹配正则表达式
        for line in note:
            # 匹配日期时间
            if date_regex.search(line):
                date_fields = date_regex.search(line).group().split()
                line_numbers[dmnum].append(date_fields[2])
            # 匹配线的起止点
            if location_regex.search(line):
                location_fields = location_regex.search(line).group().split()
                line_numbers[dmnum].append(location_fields[1])
                line_numbers[dmnum].append(location_fields[2])
            # 匹配 FIX
            if fix_regex.findall(line):
                fix_fields = fix_regex.findall(line)[0].split(" ")
                fix_fields[2] = round(float(fix_fields[2]), 3)
                fix_fields[3] = int(fix_fields[3])
                result = [fix_fields[2], fix_fields[3]]
                fix[dmnum].append(result)
            # 匹配 EC1 1
            if ec1_regex.findall(line):
                ec1_fields = ec1_regex.findall(line)[0].split(" ")
                ec1_fields[2] = round(float(ec1_fields[2]), 3)
                ec1_fields[3] = '-' + ec1_fields[3]
                ec1_fields[3] = round(float(ec1_fields[3]), 2)
                result = [ec1_fields[2], ec1_fields[3]]
                EC1[dmnum].append(result)
            #匹配POS
            if pos_regex.findall(line):
                pos_fields = pos_regex.findall(line)[0].split(" ")
                pos_fields[2] = round(float(pos_fields[2]), 3)
                pos_fields[3] = round(float(pos_fields[3]), 3)
                pos_fields[4] = round(float(pos_fields[4]), 3)
                result = [pos_fields[2], pos_fields[3], pos_fields[4]]
                POS[dmnum].append(result)
            # 处理 Add 信息
            if add_regex.findall(line):
                add_fields = add_regex.findall(line)[0].split(" ")
                add_fields[1] = int(add_fields[1])  # 序号
                add_fields[2] = round(float(add_fields[2]), 3)  # 时间
                result = [add_fields[2], add_fields[1]]
                add[dmnum].append(result)
            # 处理 Cha 信息
            if cha_regex.findall(line):
                cha_fields = cha_regex.findall(line)[0].split(" ")
                cha_fields[1] = int(cha_fields[1])  # 序号
                cha_fields[2] = float(cha_fields[2])  # 时间
                cha_fields[3] = -float(cha_fields[3])  # 原始水深
                cha_fields[4] = -float(cha_fields[4])  # 改正水深
                result = [cha_fields[2], cha_fields[1], cha_fields[3], cha_fields[4]]
                CHA[dmnum].append(result)
            # 处理 Del 信息
            if del_regex.findall(line):
                del_fields = del_regex.findall(line)[0].split(" ")
                del_fields[1] = int(del_fields[1])  # 序号
                del_fields[2] = round(float(del_fields[2]), 3)  # 时间
                result = [del_fields[2], del_fields[1]]
                ysdel[dmnum].append(result)
    #错误警告
    if len(EC1[dmnum]) == 0 :
        tkinter.messagebox.showwarning('警告', f'{notemenu[dmnum]} EC1 1 数据为空!')
    if len(POS[dmnum]) == 0 :
        tkinter.messagebox.showwarning('警告', f'{notemenu[dmnum]}pos 数据为空!')
    if len(fix[dmnum]) == 0:
        tkinter.messagebox.showwarning('警告', f'{notemenu[dmnum]}FIX  数据为空!')
    #添加点间隔判断，如果处理点间隔，干预
    if scrpoint != 0:
        new_fix = []
        new_fix.append(fix[dmnum][0])
        #取原fix第一点坐标e1,n1
        for k in range(1,len(POS[dmnum])):
            # 如果fix数前没有POS数据，就用最近POS的坐标
            if fix[dmnum][0][0] <= POS[dmnum][0][0]:
                e1 = POS[dmnum][0][1]
                n1 = POS[dmnum][0][2]
            # 如果fix数据后没有POS数据，就用最近POS的坐标
            elif fix[dmnum][0][0] >= POS[dmnum][len(POS[dmnum]) - 1][0]:
                e1 = POS[dmnum][len(POS[dmnum]) - 1][1]
                n1 = POS[dmnum][len(POS[dmnum]) - 1][2]
            elif (fix[dmnum][0][0] >= POS[dmnum][k - 1][0]) & (fix[dmnum][0][0] <= POS[dmnum][k][0]):
                t = POS[dmnum][k][0] - POS[dmnum][k - 1][0]
                t1 = fix[dmnum][0][0] - POS[dmnum][k - 1][0]
                e1 = round((t1 / t) * (POS[dmnum][k][1] - POS[dmnum][k - 1][1]) + POS[dmnum][k - 1][1], 3)
                n1 = round((t1 / t) * (POS[dmnum][k][2] - POS[dmnum][k - 1][2]) + POS[dmnum][k - 1][2], 3)
        fxh = fix[dmnum][1][1]  # 筛选后点序号,接原第一点的序号
        for i in range(1, len(POS[dmnum])):
            if (scrpoint >= math.sqrt((e1 - POS[dmnum][i - 1][1]) ** 2 + (n1 - POS[dmnum][i - 1][2]) ** 2)) & (
                    math.sqrt((e1 - POS[dmnum][i][1]) ** 2 + (n1 - POS[dmnum][i][2]) ** 2) >= scrpoint):
                # 为了运行速度，直接两个POS信号中间位置为目标。
                result = [round((POS[dmnum][i - 1][0] + POS[dmnum][i][0]) / 2, 3), fxh]  # 时间，序号
                fxh = fxh + 1
                new_fix.append(result)
                e1 = POS[dmnum][i][1]
                n1 = POS[dmnum][i][2]
        new_fix.append(fix[dmnum][len(fix[dmnum])-1])
        fix[dmnum] = new_fix
    # 内插得到fix点的水深、坐标
    for i in range(len(fix[dmnum])):
        # 处理f_z
        #如果没有EC1数据，将水深设为0
        if len(EC1[dmnum]) == 0:
            ft = fix[dmnum][i][0]
            fxh = int(fix[dmnum][i][1])
            fz = 0

        #如果有水深信号
        else:
            #如果fix数据前没有EC1 1数据，就用最近EC1 1的水深
            if fix[dmnum][i][0] <= EC1[dmnum][0][0]:
                ft = fix[dmnum][i][0]
                fxh = int(fix[dmnum][i][1])
                fz = EC1[dmnum][0][1]
            # 如果fix数据后没有EC1 1数据，就用最近EC1 1的水深
            elif fix[dmnum][i][0] >= EC1[dmnum][len(EC1[dmnum])-1][0]:
                ft = fix[dmnum][i][0]
                fxh = int(fix[dmnum][i][1])
                fz = EC1[dmnum][len(EC1[dmnum])-1][1]
            else:
                for j in range(1,len(EC1[dmnum])):
                    if (fix[dmnum][i][0] >= EC1[dmnum][j - 1][0]) & (fix[dmnum][i][0] <= EC1[dmnum][j][0]):
                        ft = fix[dmnum][i][0]
                        fxh = int(fix[dmnum][i][1])
                        fz = EC1[dmnum][j][1]
        #取POS数据里的坐标
        for k in range(1,len(POS[dmnum])):
            # 如果fix数前没有POS数据，就用最近POS的坐标
            if fix[dmnum][i][0] <= POS[dmnum][0][0]:
                fx = POS[dmnum][0][1]
                fy = POS[dmnum][0][2]
            # 如果fix数据后没有POS数据，就用最近POS的坐标
            elif fix[dmnum][i][0] >= POS[dmnum][len(POS[dmnum]) - 1][0]:
                fx = POS[dmnum][len(POS[dmnum]) - 1][1]
                fy = POS[dmnum][len(POS[dmnum]) - 1][2]
            else:
                if (fix[dmnum][i][0] >= POS[dmnum][k - 1][0]) & (fix[dmnum][i][0] <= POS[dmnum][k][0]):
                    t = POS[dmnum][k][0] - POS[dmnum][k - 1][0]
                    t1 = fix[dmnum][i][0] - POS[dmnum][k - 1][0]
                    fx = round((t1 / t) * (POS[dmnum][k][1] - POS[dmnum][k - 1][1]) + POS[dmnum][k - 1][1], 3)
                    fy = round((t1 / t) * (POS[dmnum][k][2] - POS[dmnum][k - 1][2]) + POS[dmnum][k - 1][2], 3)

        result = [ft, fxh, fx, fy, fz]  # 时间、序号、X(E)、Y(N)、Z(水深)
        FIX[dmnum].append(result)
    #设置加点数据的点号
    if len(add[dmnum]) == 0:
        XH[dmnum] =  fix[dmnum][len(fix[dmnum]) - 1][1]
    else:
        XH[dmnum] = add[dmnum][len(add[dmnum])-1][1]

    # 列表转dataframe,方便绘图和处理
    dfFIX[dmnum] = pd.DataFrame(FIX[dmnum])
    dfFIX[dmnum].columns = ['时间', '序号', 'E', 'N', '水深']
    if len(EC1[dmnum]) > 0:
        dfEC1[dmnum] = pd.DataFrame(EC1[dmnum])
        dfEC1[dmnum].columns = ['时间', '水深']
    ZZFIX[dmnum] = dfFIX[dmnum]  # 保留dfFIX,后面用ZZFIX绘图
    ys_ZZFIX[dmnum] = ZZFIX[dmnum]
    # print(ZZFIX[0])
    # 是否显示原图
    if ytfx[dmnum] == 0:
        # 根据add得到ADD、dfADD,并改变ZZFIX
        if len(add[dmnum]) != 0:
            for i in range(len(add[dmnum])):
                if add[dmnum][i][0] < EC1[dmnum][0][0]:
                    continue
                if add[dmnum][i][0] > EC1[dmnum][len(EC1[dmnum]) - 1][0]:
                    continue
                # 处理f_z
                for j in range(len(EC1[dmnum])):
                    if (add[dmnum][i][0] >= EC1[dmnum][j - 1][0]) & (add[dmnum][i][0] <= EC1[dmnum][j][0]):
                        ft = add[dmnum][i][0]
                        fxh = int(add[dmnum][i][1])
                        fz = EC1[dmnum][j][1]
                for k in range(len(POS[dmnum])):
                    if (add[dmnum][i][0] >= POS[dmnum][k - 1][0]) & (add[dmnum][i][0] <= POS[dmnum][k][0]):
                        T = POS[dmnum][k][0] - POS[dmnum][k - 1][0]
                        T1 = add[dmnum][i][0] - POS[dmnum][k - 1][0]
                        fx = round((T1 / T) * (POS[dmnum][k][1] - POS[dmnum][k - 1][1]) + POS[dmnum][k - 1][1], 3)
                        fy = round((T1 / T) * (POS[dmnum][k][2] - POS[dmnum][k - 1][2]) + POS[dmnum][k - 1][2], 3)
                result = [ft, fxh, fx, fy, fz]  # 时间、序号、Y(E),X(N)，Z(水深)
                ADD[dmnum].append(result)
                # ADD列表转dataframe,方便绘图和处理
                dfADD[dmnum] = pd.DataFrame(ADD[dmnum])
                dfADD[dmnum].columns = ['时间', '序号', 'E', 'N', '水深']
        if dfADD[dmnum].empty is False:
            ZZFIX[dmnum] = ZZFIX[dmnum].append(dfADD[dmnum])
            ZZFIX[dmnum] = ZZFIX[dmnum].sort_values(by=['时间'])  # 需要降序就加上ascending=False
            ZZFIX[dmnum] = ZZFIX[dmnum].reset_index(drop=True)  # 重新排序
            # dfADD[dmnum] = dfADD[dmnum].reset_index(drop=True)  # 重新排序
        #根据CHA改变ZZFIX、dffix、dfADD
        if len(CHA[dmnum]) != 0:
            dfCHA[dmnum] = pd.DataFrame(CHA[dmnum])
            dfCHA[dmnum].columns = ['时间', '序号', '原始水深', '改正水深']
            for i in range(len(CHA[dmnum])):
                # 在ZZFIX里改动选中的行
                ZZFIX[dmnum]['水深'][ZZFIX[dmnum]['时间'] == CHA[dmnum][i][0]] = CHA[dmnum][i][3]
                dfFIX[dmnum]['水深'][dfFIX[dmnum]['时间'] == CHA[dmnum][i][0]] = CHA[dmnum][i][3]
                dfADD[dmnum]['水深'][dfADD[dmnum]['时间'] == CHA[dmnum][i][0]] = CHA[dmnum][i][3]
        # 根据ysdel得到dfDEL
        if len(ysdel[dmnum]) != 0:
            for i in range(len(ysdel[dmnum])):
                if dfDEL[dmnum].empty:
                    dfDEL[dmnum] = ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == ysdel[dmnum][i][0]]
                else:
                    dfDEL[dmnum] = dfDEL[dmnum].append(ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == ysdel[dmnum][i][0]])
        #根据dfdel改动其他数据
        if dfDEL[dmnum].empty is False:
            # 在ZZFIX、dfFIX里删除del选中的行
            #print('之前ZZFIX', ZZFIX)
            ZZFIX[dmnum] = ZZFIX[dmnum].append(dfDEL[dmnum])       #两次append是为了稍后把dfdel里全部删掉
            ZZFIX[dmnum] = ZZFIX[dmnum].append(dfDEL[dmnum])
            ZZFIX[dmnum] = ZZFIX[dmnum].drop_duplicates(keep=False)     #删除重复行
            ZZFIX[dmnum] = ZZFIX[dmnum].reset_index(drop=True)  # 重新排序
            #print('之后ZZFIX', ZZFIX)
            dfFIX[dmnum] = dfFIX[dmnum].append(dfDEL[dmnum])
            dfFIX[dmnum] = dfFIX[dmnum].append(dfDEL[dmnum])
            dfFIX[dmnum] = dfFIX[dmnum].drop_duplicates(keep=False)
            dfFIX[dmnum] = dfFIX[dmnum].reset_index(drop=True)  # 重新排序
            # 在dfADD里删除del选中的行
            if dfADD[dmnum].empty is False:
                #print('之前dfADD', dfADD)
                dfADD[dmnum] = dfADD[dmnum].append(dfDEL[dmnum])
                #print('加一次fADD', dfADD)
                dfADD[dmnum] = dfADD[dmnum].append(dfDEL[dmnum])
                #print('加两次fADD', dfADD)
                dfADD[dmnum] = dfADD[dmnum].drop_duplicates(keep=False)  # 删除重复行
                dfADD[dmnum] = dfADD[dmnum].reset_index(drop=True)  # 重新排序
                #print('之后dfADD', dfADD)
                #ADD里删除ysdel里有的数据
                #存储删除的ADD的索引
                temp = []
                for i in range(len(ADD[dmnum])):
                    for j in range(len(ysdel[dmnum])):
                        if ADD[dmnum][i][0] == ysdel[dmnum][j][0]:
                            temp.append(i)
                if temp != []:
                    t1 = 0
                    for i in temp:
                        t = i - t1
                        ADD[dmnum].pop(t)
                        t1 += 1
            dfDEL[dmnum] = dfDEL[dmnum].drop(index=dfDEL[dmnum].index)   #清空dfdel,防止改变间隔后出现错误。
#显示及鼠标操作
def operation():
    global EC1,fix,POS,FIX,ADD,CHA,ysdel,add
    global dfDEL,dfADD,dfCHA,dfEC1,dfFIX,ZZFIX,notemenu
    global fig,fig1,XH,dmnum
    global xz_min, xz_max,yz_min, yz_max
    global range_control, Retracebox

    # print(notesection[dmnum])
    # print(notemenu[dmnum])

    ###内置处理函数###
    #每次处理重置界面操作状态、重置回撤栈。
    range_control = 0
    Retracebox = []
    # 实时拖拽水深参数
    press1 = 0
    xtrc = 0
    ytrc = 0
    #缩放
    @lru_cache(maxsize=256)
    def on_scroll(event):
        global new_xstart, new_xend, new_ystart, new_yend
        global range_control
        # xdata = event.xdata  # 获取鼠标所在位置的 x 坐标
        # ydata = event.ydata  # 获取鼠标所在位置的 y 坐标
        if event.inaxes == fig1:
            if event.button == 'up':
                scale_factor = 0.8  # 缩小比例因子
            elif event.button == 'down':
                scale_factor = 1.2  # 放大比例因子
            else:
                scale_factor = 1.0

            # 获取鼠标点击的坐标位置
            x_mouse = event.xdata
            y_mouse = event.ydata

            # 获取当前坐标轴的范围
            xstart, xend = fig1.get_xlim()
            ystart, yend = fig1.get_ylim()

            # 计算当前范围中心点坐标
            xcenter = (xstart + xend) / 2
            ycenter = (ystart + yend) / 2

            # 计算缩放后的新范围
            new_xrange = (xend - xstart) * scale_factor
            new_yrange = (yend - ystart) * scale_factor

            # 计算新的中心点坐标
            new_xcenter = x_mouse - (x_mouse - xcenter) * scale_factor
            new_ycenter = y_mouse - (y_mouse - ycenter) * scale_factor

            # 计算新的范围
            new_xstart = new_xcenter - new_xrange / 2
            new_xend = new_xcenter + new_xrange / 2
            new_ystart = new_ycenter - new_yrange / 2
            new_yend = new_ycenter + new_yrange / 2

            # 更新坐标轴范围
            fig1.set_xlim(new_xstart, new_xend)
            fig1.set_ylim(new_ystart, new_yend)
            range_control = 1  # 表示范围被改动，下次画图按改动后范围画图
            fig.canvas.draw_idle()  # 更新画布显示
            on_scroll.cache_clear()  #清除装饰器缓存

    # 鼠标中键拖拽
    def on_press(event):
        global press2, lastx, lasty
        if event.inaxes ==fig1 :  # 判断鼠标是否在axes内
            if event.button == 2 or event.button == 3: # 判断按下的是否为鼠标滚轮键、或者右键，防止有人滚轮键不灵
                press2 = 1
                lastx = event.xdata  # 获取鼠标按下时的坐标X
                lasty = event.ydata  # 获取鼠标按下时的坐标Y
    @lru_cache(maxsize=256)
    def on_move(event):
        global range_control
        if (event.inaxes == fig1) & (press2 == 1):
            # 计算新的坐标原点并移动
            # 获取当前最新鼠标坐标与按下时坐标的差值
            dx = event.xdata - lastx
            dy = event.ydata - lasty
            # 获取当前原点和最大点的4个位置
            global new_xstart, new_xend, new_ystart, new_yend
            # 获取当前坐标轴的范围
            xstart, xend = fig1.get_xlim()
            ystart, yend = fig1.get_ylim()
            new_xstart = xstart - dx
            new_xend = xend - dx
            new_ystart = ystart - dy
            new_yend = yend - dy
            range_control = 1  # 表示范围被改动，下次画图按改动后范围画图
            fig1.set_xlim(new_xstart, new_xend)
            fig1.set_ylim(new_ystart, new_yend)
            fig1.figure.canvas.draw()  # 更新画布
    def on_release(event):
        global press2
        if press2:
            press2 = 0  # 鼠标松开，结束绘制
            on_move.cache_clear()  # 清空缓存
    # 加点
    def on_add(event):
        global XH
        global dfADD, ZZFIX, ADD, Retracebox
        global new_xstart, new_xend, new_ystart, new_yend
        global addbj
        if event.inaxes:  # 判断鼠标是否在axes内
            if (event.button == 1) & (addbj == 1):  # 判断按下的是否为鼠标滚轮键
                # addbj = 0
                xadd = round(event.xdata, 3)
                # 内插得到add点的水深、坐标
                if xadd < EC1[dmnum][0][0]:
                    pass
                elif xadd > EC1[dmnum][len(EC1[dmnum]) - 1][0]:
                    pass
                else:
                    XH[dmnum] = XH[dmnum] + 1
                    for j in range(len(EC1[dmnum])):
                        if (xadd >= EC1[dmnum][j - 1][0]) & (xadd <= EC1[dmnum][j][0]):
                            ft = xadd
                            fz = EC1[dmnum][j][1]
                    for k in range(len(POS[dmnum])):
                        if (xadd >= POS[dmnum][k - 1][0]) & (xadd <= POS[dmnum][k][0]):
                            T = POS[dmnum][k][0] - POS[dmnum][k - 1][0]
                            T1 = xadd - POS[dmnum][k - 1][0]
                            fx = round((T1 / T) * (POS[dmnum][k][1] - POS[dmnum][k - 1][1]) + POS[dmnum][k - 1][1], 3)
                            fy = round((T1 / T) * (POS[dmnum][k][2] - POS[dmnum][k - 1][2]) + POS[dmnum][k - 1][2], 3)
                    result = [ft, XH[dmnum], fx, fy, fz]  # 时间、序号，Y(E)、X(N)，Z(水深)

                    ADD[dmnum].append(result)
                    dfADD[dmnum] = pd.DataFrame(ADD[dmnum])
                    dfADD[dmnum].columns = ['时间', '序号', 'E', 'N', '水深']

                    # 在txt上记录加点情况
                    if result != []:
                        addnote = open(f"{notemenu[dmnum]}", 'a')
                        addnote.write('Add %s %s %s \n'%(XH[dmnum],ft,-fz))
                        addnote.close()

                    # 处理用来成图的ZZFIX数组
                    if dfADD[dmnum].empty is False:
                        ZZFIX[dmnum] = ZZFIX[dmnum].append(dfADD[dmnum].iloc[dfADD[dmnum].shape[0] - 1])
                        ZZFIX[dmnum] = ZZFIX[dmnum].sort_values(by=['时间'])  # 需要降序就加上ascending=False
                        ZZFIX[dmnum] = ZZFIX[dmnum].reset_index(drop=True)  # 重新排序
                        dfADD[dmnum] = dfADD[dmnum].reset_index(drop=True)  # 重新排序
                    # print('dfadd',dfADD[dmnum])
                    plot_data()
                    # 保证加点时屏幕位置不变
                    # if new_xstart == 0:
                    if range_control == 0:
                        new_xstart, new_xend = event.inaxes.get_xlim()
                        new_ystart, new_yend = event.inaxes.get_ylim()
                    fig1.set_xlim(new_xstart, new_xend)
                    fig1.set_ylim(new_ystart, new_yend)
                    fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
                    Retracebox.append('retadd')
                    #print('add操作之后', ADD[dmnum])
    # 删点
    def on_del(event):
        global delbj
        global new_xstart, new_xend, new_ystart, new_yend
        global dfDEL, ZZFIX, dfADD, ADD, dfFIX, Remove_source, Retracebox
        if event.inaxes:  # 判断鼠标是否在axes内
            if (event.button == 1) & (delbj == 1):
                # delbj = 0
                xdel = round(event.xdata, 3)
                # 寻找ZZFIX['时间'] - xdel差值最小处的索引
                idx = (ZZFIX[dmnum]['时间'] - xdel).abs().idxmin()
                # 取该点的序号、时间、水深
                xh = ZZFIX[dmnum].loc[idx, '序号']
                xdel = ZZFIX[dmnum].loc[idx, '时间']
                ydel = ZZFIX[dmnum].loc[idx, '水深']

                if dfDEL[dmnum].empty:
                    dfDEL[dmnum] = ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == xdel]
                    dfDEL[dmnum] = dfDEL[dmnum].reset_index(drop=True)  # 重新排序
                    # print(dfDEL[dmnum])
                else:
                    dfDEL[dmnum] = dfDEL[dmnum].append(ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == xdel])
                    # dfDEL[dmnum]= dfDEL[dmnum].sort_values(by=['时间'])  # 需要降序就加上ascending=False
                    dfDEL[dmnum] = dfDEL[dmnum].reset_index(drop=True)  # 重新排序
                # 在txt上记录删点情况
                delnote = open(f"{notemenu[dmnum]}", 'a')
                delnote.write('Del %s %s %s \n' % (int(xh),xdel,-ydel))
                delnote.close()


                # 将dfDEL最新的时间取出，若ZZFIX['时间']有与其相等，则ZZFIX弹出该行
                ZZFIX[dmnum] = ZZFIX[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])  # 两次append是为了稍后把dfdel里全部删掉
                ZZFIX[dmnum] = ZZFIX[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])
                ZZFIX[dmnum] = ZZFIX[dmnum].drop_duplicates(keep=False)  # 删除重复行
                ZZFIX[dmnum] = ZZFIX[dmnum].reset_index(drop=True)  # 重新排序
                # 在dfFIX里删除del选中的行
                r1 = len(dfFIX[dmnum])
                dfFIX[dmnum] = dfFIX[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])  # 两次append是为了稍后把dfdel里全部删掉
                dfFIX[dmnum] = dfFIX[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])
                dfFIX[dmnum] = dfFIX[dmnum].drop_duplicates(keep=False)  # 删除重复行
                dfFIX[dmnum] = dfFIX[dmnum].reset_index(drop=True)  # 重新排序
                if r1 != len(dfFIX[dmnum]):
                    Remove_source.append('FIX')
                # 在dfADD里删除del选中的行
                if dfADD[dmnum].empty is False:
                    r2 = len(dfADD[dmnum])
                    dfADD[dmnum] = dfADD[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])  # 两次append是为了稍后把dfdel里全部删掉
                    dfADD[dmnum] = dfADD[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])
                    dfADD[dmnum] = dfADD[dmnum].drop_duplicates(keep=False)  # 删除重复行
                    dfADD[dmnum] = dfADD[dmnum].reset_index(drop=True)  # 重新排序
                    # 列表推导式删选ADD中不含del最后一列的列表的值，将其返回给ADD
                    ADD[dmnum] = [row for row in ADD[dmnum] if not set(row) & set(dfDEL[dmnum].tail(1).iloc[0].values.tolist())]
                    if r2 != len(dfADD[dmnum]):
                        Remove_source.append('ADD')

                plot_data()
                # 保证删点时屏幕位置不变
                if range_control == 0:
                    new_xstart, new_xend = event.inaxes.get_xlim()
                    new_ystart, new_yend = event.inaxes.get_ylim()

                fig1.set_xlim(new_xstart, new_xend)
                fig1.set_ylim(new_ystart, new_yend)
                fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
                Retracebox.append('retdel')
    # 改点
    def on_cha(event):
        global chabj
        global new_xstart, new_xend, new_ystart, new_yend
        global dfCHA, dfDEL, ZZFIX, dfADD, ADD, dfFIX, CHA, Retracebox
        if event.inaxes:  # 判断鼠标是否在axes内
            if (event.button == 1) & (chabj == 1):  # 判断按下的是否为鼠标滚轮键
                # chabj = 0
                xcha = round(event.xdata, 3)
                # 寻找ZZFIX['时间'] - xcha差值最小处的索引
                idx = (ZZFIX[dmnum]['时间'] - xcha).abs().idxmin()
                # 取该点的序号、时间、水深
                xh = int(ZZFIX[dmnum].loc[idx, '序号'])
                xcha = ZZFIX[dmnum].loc[idx, '时间']
                ysycha = ZZFIX[dmnum].loc[idx, '水深']
                # 窗口主体框架
                CHAN = Toplevel()
                CHAN.title('改正水深')
                CHAN.resizable(False, False)  # 横纵均不允许调整
                CHAN.attributes("-toolwindow", True)
                # 窗体居中
                a, b = 600, 150  # a为窗体宽度，b为窗体的高度
                c = (CHAN.winfo_screenwidth() - a) / 2  # (屏幕宽度-窗体宽度)/2
                d = (CHAN.winfo_screenheight() - b) / 2  # (屏幕高度-窗体高度)/2
                CHAN.geometry('%dx%d+%d+%d' % (a, b, c, d))

                if 'normal' == CHAN.state():  # 保证窗口强制弹出
                    CHAN.focus_set()
                    CHAN.master.attributes('-disabled', True)  # 禁用主窗口

                def close_settings_window():  # 关闭子窗口时，启用主窗口
                    CHAN.destroy()
                    root.attributes('-disabled', False)
                    root.focus_force()

                def but1():
                    global new_xstart, new_xend, new_ystart, new_yend
                    nonlocal xcha, ysycha

                    try:
                        bjcha = float('-' + entry1.get())
                        #print(bjcha)
                    except:
                        tkinter.messagebox.showwarning('警告', '请正确输入改正水深!')
                        close_settings_window()

                    result = [xcha, xh, ysycha, bjcha]
                    #print(result)
                    CHA[dmnum].append(result)
                    dfCHA[dmnum] = pd.DataFrame(CHA[dmnum])
                    dfCHA[dmnum].columns = ['时间', '序号', '原始水深', '改正水深']
                    # print(dfCHA[dmnum])

                    # 将结果写入txt
                    chanote = open(f"{notemenu[dmnum]}", 'a')
                    chanote.write(f"Cha {int(dfCHA[dmnum].iloc[-1]['序号'])} "
                                  f"{dfCHA[dmnum].iloc[-1]['时间']} "
                                  f"{-dfCHA[dmnum].iloc[-1]['原始水深']} "
                                  f"{-dfCHA[dmnum].iloc[-1]['改正水深']}\n")
                    chanote.close()

                    # 在ZZFIX、dffix里改动选中的行
                    ZZFIX[dmnum]['水深'][ZZFIX[dmnum]['时间'] == xcha] = result[3]
                    dfFIX[dmnum]['水深'][dfFIX[dmnum]['时间'] == xcha] = result[3]
                    dfADD[dmnum]['水深'][dfADD[dmnum]['时间'] == xcha] = result[3]

                    Retracebox.append('retcha')
                    plot_data()
                    # 保证改点时屏幕位置不变
                    if range_control == 0:
                        new_xstart, new_xend = event.inaxes.get_xlim()
                        new_ystart, new_yend = event.inaxes.get_ylim()

                    fig1.set_xlim(new_xstart, new_xend)
                    fig1.set_ylim(new_ystart, new_yend)
                    fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
                    new_xstart = 0  # 标记范围
                    close_settings_window()

                CHAN.protocol('WM_DELETE_WINDOW', lambda: close_settings_window(CHAN, root))  # WM_DELETE_WINDOW 窗口删除时
                # 执行lambda函数

                # Label框
                lb1 = Label(CHAN, text=f'第{xh}点的改正水深绝对值', font=('楷体', 20))
                lb1.place(relx=0.05, rely=0.1, relheight=0.25)  # place布局

                # Entry框
                entry1 = Entry(CHAN, font=('楷体', 17))
                entry1.place(relx=0.05, rely=0.7, relwidth=0.9, relheight=0.25)
                entry1.delete(0, 'end')
                entry1.insert(0, -ysycha)
                # Button按钮
                button1 = Button(CHAN, text='确定', font=('楷体', 20), command=lambda: but1())
                button2 = Button(CHAN, text='取消', font=('楷体', 20), command=lambda: close_settings_window())
                button1.place(relx=0.7, rely=0.1, relwidth=0.25, relheight=0.25)
                button2.place(relx=0.7, rely=0.4, relwidth=0.25, relheight=0.25)

                CHAN.mainloop()
                #print(on_cha)
    # 回撤
    def Retracement():
        global delbj
        global dfDEL, ZZFIX, dfADD, ADD, dfFIX, CHA, dfCHA, Remove_source, Retracebox
        global XH
        global new_xstart, new_xend, new_ystart, new_yend
        global addbj, delbj, chabj, rtcha
        addbj = 0
        delbj = 0
        chabj = 0
        rtcha = 0
        root.config(cursor="arrow") #关闭增删改操作并把鼠标变回箭头
        if len(Retracebox) > 0:
            ret = Retracebox.pop()
            if ret == 'retadd':
                # add函数的逆运算
                if len(ADD[dmnum]) == 1:
                    dfADD[dmnum] = pd.DataFrame()
                if len(ADD[dmnum]) > 1:
                    # 删除最后一个数据帧
                    dfADD[dmnum] = pd.DataFrame(ADD[dmnum][:-1])
                    dfADD[dmnum].columns = ['时间', '序号', 'E', 'N', '水深']
                # 删除 ZZFIX[dmnum] 中的对应行
                del_row = ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == ADD[dmnum][-1][0]]
                ZZFIX[dmnum] = ZZFIX[dmnum].append(del_row)  # 先append再排重
                ZZFIX[dmnum] = ZZFIX[dmnum].drop_duplicates(keep=False)  # 删除重复行
                ZZFIX[dmnum] = ZZFIX[dmnum].reset_index(drop=True)  # 重新排序
                # 更新ADD中的数据和XH
                ADD[dmnum].pop()
                XH[dmnum] = XH[dmnum] - 1
                plot_data()
                # 保证还原时屏幕位置不变
                if range_control == 0:
                    new_xstart, new_xend = fig1.get_xlim()
                    new_ystart, new_yend = fig1.get_ylim()
                fig1.set_xlim(new_xstart, new_xend)
                fig1.set_ylim(new_ystart, new_yend)
                fig.canvas.draw_idle()
                #在txt删除一行操作
                with open(f"{notemenu[dmnum]}", 'a') as f:
                    # 定位到倒数第二行末尾
                    f.seek(-2, 2)
                    while f.read(1) != '\n':
                        f.seek(-2, 1)
                    # 清空最后一行内容
                    f.seek(f.tell() + 1, 0)
                    f.truncate()
            if ret == 'retdel':
                # del函数的逆运算
                if len(Remove_source) > 0:
                    Last_Delete = Remove_source.pop()
                    # print('Last_delete',Last_Delete)
                    # 按记录分别加到不同的dataframe、列表
                    if Last_Delete == 'FIX':
                        dfFIX[dmnum] = dfFIX[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])
                        dfFIX[dmnum] = dfFIX[dmnum].reset_index(drop=True)  # 重新排序
                    if Last_Delete == 'ADD':
                        dfADD[dmnum] = dfADD[dmnum].append(dfDEL[dmnum].tail(1).iloc[0])
                        dfADD[dmnum] = dfADD[dmnum].reset_index(drop=True)  # 重新排序
                        ADD[dmnum].append(dfDEL[dmnum].tail(1).iloc[0].values.tolist())
                    # 加点到ZZFIX
                    ZZFIX[dmnum] = ZZFIX[dmnum].append(dfDEL[dmnum].tail(1))
                    ZZFIX[dmnum] = ZZFIX[dmnum].sort_values(by=['时间'])  # 需要降序就加上ascending=False
                    ZZFIX[dmnum] = ZZFIX[dmnum].reset_index(drop=True)  # 重新排序
                    # 删除dfdel已处理过的行
                    dfDEL[dmnum] = dfDEL[dmnum].drop(dfDEL[dmnum].index[-1])
                    plot_data()

                    # 保证还原时屏幕位置不变
                    if range_control == 0:
                        new_xstart, new_xend = fig1.get_xlim()
                        new_ystart, new_yend = fig1.get_ylim()

                    fig1.set_xlim(new_xstart, new_xend)
                    fig1.set_ylim(new_ystart, new_yend)
                    fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
                    # 在txt删除一行操作
                    with open(f"{notemenu[dmnum]}", 'a') as f:
                        # 定位到倒数第二行末尾
                        f.seek(-2, 2)
                        while f.read(1) != '\n':
                            f.seek(-2, 1)
                        # 清空最后一行内容
                        f.seek(f.tell() + 1, 0)
                        f.truncate()
            if ret == 'retcha':
                cha_row = dfCHA[dmnum].tail(1).iloc[0].values.tolist()
                ZZFIX[dmnum]['水深'][ZZFIX[dmnum]['时间'] == cha_row[0]] = cha_row[2]
                # print('之前',CHA[dmnum],dfCHA[dmnum])
                CHA[dmnum].pop()
                dfCHA[dmnum] = dfCHA[dmnum].drop(dfCHA[dmnum].tail(1).index)
                # print('之后', CHA[dmnum], dfCHA[dmnum])
                plot_data()
                # 保证还原时屏幕位置不变
                if range_control == 0:
                    new_xstart, new_xend = fig1.get_xlim()
                    new_ystart, new_yend = fig1.get_ylim()
                fig1.set_xlim(new_xstart, new_xend)
                fig1.set_ylim(new_ystart, new_yend)
                fig.canvas.draw_idle()
                # 在txt删除一行操作
                with open(f"{notemenu[dmnum]}", 'a') as f:
                    # 定位到倒数第二行末尾
                    f.seek(-2, 2)
                    while f.read(1) != '\n':
                        f.seek(-2, 1)
                    # 清空最后一行内容
                    f.seek(f.tell() + 1, 0)
                    f.truncate()
    # 实时拖拽水深
    def change_click(event):
        global rtcha
        nonlocal press1, xtrc, ytrc
        if event.inaxes == fig1:  # 判断鼠标是否在axes内
            if (event.button == 1) & (rtcha == 1):  # 判断按下的是否为鼠标滚轮键
                press1 = 1
                xtrc = round(event.xdata, 3)
                # 寻找ZZFIX['时间'] - xdel差值最小处的索引
                idx = (ZZFIX[dmnum]['时间'] - xtrc).abs().idxmin()
                xtrc = ZZFIX[dmnum].loc[idx, '时间']
                ytrc = ZZFIX[dmnum]['水深'][ZZFIX[dmnum]['时间'] == xtrc].values.tolist()[0]
                # print(xtrc)
                # print(ytrc)
    def change_move(event):
        global ZZFIX, CHA,dfFIX,dfADD
        global new_xstart, new_xend, new_ystart, new_yend
        if (event.inaxes == fig1) & (press1 == 1):

            y = round(event.ydata, 2)
            # 在ZZFIX里改动选中的行
            ZZFIX[dmnum]['水深'][ZZFIX[dmnum]['时间'] == xtrc] = y
            dfFIX[dmnum]['水深'][dfFIX[dmnum]['时间'] == xtrc] = y
            dfADD[dmnum]['水深'][dfADD[dmnum]['时间'] == xtrc] = y
            plot_data()

            if range_control == 0:
                new_xstart, new_xend = event.inaxes.get_xlim()
                new_ystart, new_yend = event.inaxes.get_ylim()
            fig1.set_xlim(new_xstart, new_xend)
            fig1.set_ylim(new_ystart, new_yend)
            fig.canvas.draw_idle()  # 绘图动作实时反映在图像上
            # fig1.annotate(f'水深: {y:.2f}', xy=(x, y), xytext=(x + 0.5, y + 0.5),
            #                      arrowprops=dict(facecolor='black', shrink=0.05))
    def change_release(event):
        global rtcha, dfCHA, CHA, Retracebox
        nonlocal press1
        if press1 == 1:
            # rtcha = 0
            press1 = 0
            # 将更改结果记录进CHA,dfcha
            time_temp = ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == xtrc].iloc[0, 0]
            xh_temp = ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == xtrc].iloc[0, 1]
            shuishen_temp = ZZFIX[dmnum][ZZFIX[dmnum]['时间'] == xtrc].iloc[0, 4]
            result = [time_temp, xh_temp, ytrc, shuishen_temp]
            CHA[dmnum].append(result)
            dfCHA[dmnum] = pd.DataFrame(CHA[dmnum])
            dfCHA[dmnum].columns = ['时间', '序号', '原始水深', '改正水深']
            #将结果写入txt
            chanote = open(f"{notemenu[dmnum]}", 'a')
            chanote.write(f"Cha {int(dfCHA[dmnum].iloc[-1]['序号'])} "
                          f"{dfCHA[dmnum].iloc[-1]['时间']} "
                          f"{-dfCHA[dmnum].iloc[-1]['原始水深']} "
                          f"{-dfCHA[dmnum].iloc[-1]['改正水深']}\n")
            chanote.close()
            Retracebox.append('retcha')
    # 绑定鼠标控件
    def bind():
        global conmouse
        fig.canvas.mpl_connect("button_press_event", on_press)
        fig.canvas.mpl_connect("button_release_event", on_release)
        fig.canvas.mpl_connect("motion_notify_event", on_move)
        fig.canvas.mpl_connect('scroll_event', on_scroll)
        fig.canvas.mpl_connect("button_press_event", on_add)
        fig.canvas.mpl_connect("button_press_event", on_del)
        fig.canvas.mpl_connect("button_press_event", on_cha)
        fig.canvas.mpl_connect('button_press_event', change_click)
        fig.canvas.mpl_connect('motion_notify_event', change_move)
        fig.canvas.mpl_connect('button_release_event', change_release)
        conmouse = 1
    if conmouse != 1:
        bind()
    mainmenu.entryconfigure('撤销(Z)', underline=3, command=lambda: Retracement())
    plot_data()
#绘图
def plot_data():
    global fig, fig1
    #global xz_min, xz_max, yz_min, yz_max
    # 绘图部分
    fig1.cla()
    # 添加x轴和y轴标签
    fig1.set_xlabel('时间')
    fig1.set_ylabel('水深')
    #fig1.set_xticks(ZZFIX[dmnum]['序号'])
    #fig1.set_xticklabels(ZZFIX[dmnum]['序号'])
    # 添加标题
    if ytfx[dmnum] ==0:
        fig1.set_title('%s'%notemenu[dmnum])
    else:
        fig1.set_title('%s原图' % notemenu[dmnum])
    try:
        if len(EC1[dmnum]) > 0:
            fig1.plot(dfEC1[dmnum]['时间'], dfEC1[dmnum]['水深'], color='black', linewidth=0.6, linestyle='-') # 画线，EC1[dmnum]
        fig1.plot(ZZFIX[dmnum]['时间'], ZZFIX[dmnum]['水深'], color='lime', linewidth=0.7, linestyle='-')  # 画第二条线,fix线
        # 一些布局、处理参数
        #xz_min, xz_max = fig1.get_xlim()
        yz_min, yz_max = fig1.get_ylim()
        fig1.vlines(dfFIX[dmnum]['时间'], yz_min, yz_max, linestyles='-', colors='red', linewidth=0.7)
        if dfADD[dmnum].empty is False:
            fig1.vlines(dfADD[dmnum]['时间'], yz_min, yz_max, linestyles='-', colors='blue', linewidth=0.7)
        # 添加序号、水深标签
        for x, y,z in zip(ZZFIX[dmnum]['时间'],ZZFIX[dmnum]['水深'],ZZFIX[dmnum]['序号']):
            plt.annotate(int(z), xy=(x, yz_min), xytext=(-5, -12),
                         textcoords='offset points',
                         arrowprops=dict(arrowstyle='-', color='none'),
                         fontsize=12, color='black',weight='bold')
            plt.annotate(str(y), xy=(x, y), xytext=(-15, -5),
                         textcoords='offset points',
                         arrowprops=dict(arrowstyle='-', color='none'),
                         fontsize=14, color='black', weight='bold')
            #plt.text(x, yz_min, str(int(z)), ha='center', va='bottom', fontsize=12, color='black')
            #plt.text(x, y, str(y), ha='center', va='bottom', fontsize=14, color='black')
    except:
        pass
#按dy0格式输出ZZFIX点
def export_ZZFIX():
    measure_date = line_numbers[0][0][:2] + line_numbers[0][0][3:5]  #取第一天线月日
    dy0_path = os.path.join(os.path.dirname(os.path.dirname(notemenu[0])), 'dy0')  #得到目标路径
    if os.path.exists(dy0_path):  # 如果文件夹已存在
        os.chdir(dy0_path)  # 切换工作路径到'dy0'
    else:
        os.mkdir(dy0_path)  # 创建'dy0'
        os.chdir(dy0_path)  # 切换工作路径到'dy0'
    #写dy0文件最开头文件信息
    with open(f'{ys_ss}{measure_date}.dy0', 'w') as file:
        n=1
        #表头
        file.write(f'- - -  {line_numbers[0][0]}  - - - - -')
        file.write('\n')  # 写入换行符
        file.write(f'{measure_date}.DY0\n')
        file.write('\n')  # 写入换行符

    #各断面信息
    with open(f'{ys_ss}{measure_date}.dy0', 'a', encoding='utf-8') as file:
        for i in range(len(ZZFIX)):
            try:
                dmnum = i
                dm_name = os.path.splitext(os.path.basename(notemenu[dmnum]))[0]  # 取文件名不带后缀
                #处理生成用来写入txt的dataframe
                if ys_ss == 'ss':
                    export_ZZFIX = ZZFIX[dmnum]
                else:
                    export_ZZFIX = ys_ZZFIX[dmnum]
                # 处理export_ZZFIX至满足输出要求
                export_ZZFIX['序号'] = export_ZZFIX['序号'].astype(int)
                export_ZZFIX['24time'] = export_ZZFIX['时间'].astype(int).apply(TimeConverter.seconds_to_time)
                export_ZZFIX['索引'] = export_ZZFIX.index + 1
                export_ZZFIX['凑格式'] = '4-4'
                export_ZZFIX['水深'] = -export_ZZFIX['水深']

                export_ZZFIX = export_ZZFIX.fillna('')  # 去空值影响
                # 创建一个新的列，并用0填充所有元素
                export_ZZFIX['操作'] = 0
                if not dfADD[dmnum].empty or not dfCHA[dmnum].empty:
                    # 找到在dfADD中出现过的行，并将对应的元素标记为1
                    if '时间' in dfADD[dmnum].columns:
                        export_ZZFIX.loc[export_ZZFIX['时间'].isin(dfADD[dmnum]['时间']), '操作'] += 1
                    # 找到在dfCHA中出现过的行，并将对应的元素标记为2
                    if '时间' in dfCHA[dmnum].columns:
                        export_ZZFIX.loc[export_ZZFIX['时间'].isin(dfCHA[dmnum]['时间']), '操作'] += 2
                export_ZZFIX = export_ZZFIX[['索引', '序号', '凑格式', '24time', 'E', 'N', '水深', '时间','操作']]
                export_ZZFIX = export_ZZFIX.fillna('')  # 去空值影响

                # 断面号，断面线起止点
                file.write(f'{dm_name}\n')
                file.write('\n')  # 写入换行符
                if line_numbers[dmnum][1]>line_numbers[dmnum][3]:
                    file.write(f'{line_numbers[dmnum][1]}' + '    ' + f'{line_numbers[dmnum][2]}\n')
                    file.write(f'{line_numbers[dmnum][3]}' + '    ' + f'{line_numbers[dmnum][4]}\n')
                else:
                    file.write(f'{line_numbers[dmnum][3]}' + '    ' + f'{line_numbers[dmnum][4]}\n')
                    file.write(f'{line_numbers[dmnum][1]}' + '    ' + f'{line_numbers[dmnum][2]}\n')
                file.write('\n')  # 写入换行符
                #ZZFIX[dmnum]
                for _, row in export_ZZFIX.iterrows():
                    file.write('{:>3}{:>5}{:>7}{:>12}{:>12.2f}{:>13.2f}{:>7.2f}{:>7}{:>6}\n'.format(
                        *row[:7], int(row[7]), *row[8:]))

                #每条断面结束句
                file.write(f'- - - - - -第{n}线结束 - - - - - - - - - - - - - - - - - - - - -\n')
                n = n + 1
                file.write('\n')  # 写入换行符
            except:
                pass
    label3.config(text=f"{dy0_path}\{ys_ss}{measure_date}.dy0输出成功")
#按dy0格式输出原始ZZFIX点
def ysexport_ZZFIX():
    global ys_ss
    ys_ss = 'ys'
    export_ZZFIX()
    ys_ss = 'ss'
###tkinter窗体布局###
root = Tk()  # 创建主窗体
root.title('皖江绘1.0')
root.geometry('360x240+450+150')
root.state("zoomed")  #最大化显示
mainmenu = Menu(root)
mainmenu.add_command(label="调用数据文件",command=lambda:import_date())  # 添加到主菜单上
mainmenu.add_command(label="撤销(Z)")  # 添加到主菜单上
mainmenu.add_command(label="鼠标修改(M)",underline=5,command=lambda:btimt_d_bj())  # 添加到主菜单上
mainmenu.add_command(label="更改(C)",underline=3,command=lambda:cha())  # 添加到主菜单上
mainmenu.add_command(label="添加(A)",underline=3,command=lambda:radd())  #alt+label的第4(underline=3)个字符是快捷键
mainmenu.add_command(label="删除(D)",underline=3,command=lambda:dele())  # 添加到主菜单上
mainmenu.add_command(label="原画复现",command=lambda:ytfxbj())  # 添加到主菜单上
mainmenu.add_command(label="上一断面",command=lambda:dmdec())  # 添加到主菜单上
mainmenu.add_command(label="下一断面",command=lambda:dminc())  # 添加到主菜单上
mainmenu.add_command(label="帮助")  # 添加到主菜单上
mainmenu.add_command(label="实况输出",command=lambda:export_ZZFIX())  # 添加到主菜单上
mainmenu.add_command(label="原始输出",command=lambda:ysexport_ZZFIX())  # 添加到主菜单上
# 创建Frame
frame = Frame(root)
frame.pack(side=TOP,fill=X, padx=5, pady=2)
#断面切换组合框
label1 = Label(frame, text="选择断面", anchor=W)
label1.pack(side=LEFT)

combo_box = ttk.Combobox(frame, values=notemenu, state="readonly", width=20)
combo_box.bind('<<ComboboxSelected>>', select_section)
combo_box.pack(side=LEFT, padx=0, pady=0,anchor=W)

button1 = Button(frame, text="上一条", anchor=W,command=dmdec)
button1.pack(side=LEFT, padx=5, pady=0)

button2 = Button(frame, text="下一条", anchor=W,command=dminc)
button2.pack(side=LEFT, padx=5, pady=0)
#点筛选组合框
label2 = Label(frame, text="Fix点距", anchor=W)
label2.pack(side=LEFT,padx=(100,5), pady=0)

entrypiont = Entry(frame)
entrypiont.pack(side=LEFT,padx=5, pady=0)

button3 = Button(frame, text="确定", anchor=W,command=lambda:screen_point())
button3.pack(side=LEFT, padx=5, pady=0)
#提示加载进度，输出位置
label3 = Label(frame, text="", anchor=W)
label3.pack(side=LEFT, padx=(100, 5), pady=0)
#菜单放在root上
root.config(menu=mainmenu)
root.mainloop()

